package com.henghe.frame.ddl.runner;

import com.henghe.frame.ddl.constant.DdlConstant;
import com.henghe.frame.ddl.mapper.DdlMapper;
import com.henghe.frame.ddl.pojo.ColumnVo;
import com.henghe.frame.ddl.pojo.TableColumnEntity;
import com.henghe.frame.ddl.pojo.TableEntity;
import com.henghe.frame.ddl.pojo.mysql.MysqlTableEntity;
import com.henghe.frame.ddl.pojo.postgres.PostgresTableEntity;
import com.henghe.frame.ddl.util.mysql.MysqlDdlUtil;
import com.henghe.frame.ddl.util.postgres.PostgresDbUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Description:
 * Author: LiuWenQing
 * Datetime: 2023/9/26 10:19
 */
@Component
@Slf4j
@MapperScan("com.henghe.frame.ddl.mapper")
@Order(8)
public class DdlRunner implements ApplicationListener<ContextRefreshedEvent> {

    @Value("${henghe.ddl-config.path}")
    private String path;
    @Value("${henghe.ddl-config.schema}")
    public String schema;
    @Value("${henghe.ddl-config.db-name}")
    private String dbName;
    @Value("${henghe.ddl-config.type}")
    private String dbType;
    @Value("${henghe.ddl-config.engine-type}")
    private String engineType;
    @Value("${henghe.ddl-config.mode}")
    private String ddlMode;
    @Autowired
    private DdlMapper ddlMapper;

    /**
     * 自动补全表结构
     * @param event the event to respond to
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        log.info(".......开始同步" + dbType + "表结构");
        switch (dbType) {
            case DdlConstant.MYSQL:
                List<TableEntity> tableEntities = MysqlDdlUtil.getCodeDb(path, engineType);
                List<String> tableNames = ddlMapper.getTablesForMysql(schema);
                List<ColumnVo> columnVos = ddlMapper.getColumnInfoForMysql(schema);
                columnVos.forEach(ColumnVo::handleLength);
                for (TableEntity tableEntity : tableEntities) {
                    MysqlTableEntity mysqlTableEntity = (MysqlTableEntity) tableEntity;
                    Optional<String> any = tableNames.stream().filter(e -> e.equals(mysqlTableEntity.getTableName())).findAny();
                    if (any.isPresent()) {
                        // 找到表
                        List<ColumnVo> nowTableColumn = columnVos.stream().filter(e -> e.getTableName().equals(any.get())).collect(Collectors.toList());
                        for (TableColumnEntity column : tableEntity.getColumns()) {
                            Optional<ColumnVo> any1 = nowTableColumn.stream().filter(e -> e.getColumnName().equals(column.getName())).findAny();
                            if (any1.isPresent() && Arrays.asList("auto", "update").contains(ddlMode)) {
                                // 找到匹配字段 判断是否改动
                                Boolean aBoolean = MysqlDdlUtil.columnCheck(column, any1.get());
                                if (!aBoolean) {
                                    String sql = MysqlDdlUtil.updateColumn(column, any.get());
                                    ddlMapper.doExcuteSql(sql);
                                }
                            } else {
                                if (!any1.isPresent()) {
                                    // 增加字段
                                    String sql = MysqlDdlUtil.addColumn(column, any.get());
                                    ddlMapper.doExcuteSql(sql);
                                }
                            }
                        }
                        // 可删除权限
                        if (ddlMode.equals("auto")) {
                            List<ColumnVo> dropColumns = nowTableColumn.stream().filter(e ->
                                            !tableEntity.getColumns().stream().map(a -> a.getName()).collect(Collectors.toList()).contains(e.getColumnName()))
                                    .collect(Collectors.toList());
                            dropColumns.forEach(e -> {
                                String sql = MysqlDdlUtil.deleteColumn(e, e.getTableName());
                                ddlMapper.doExcuteSql(sql);
                            });
                        }
                    } else {
                        String sql = MysqlDdlUtil.generateTable(mysqlTableEntity);
                        if (StringUtils.isNotEmpty(sql))
                            ddlMapper.doExcuteSql(sql);
                    }
                }
                break;
            case DdlConstant.DM:
                break;
            case DdlConstant.PG:
                List<TableEntity> tableEntitiesForPG = PostgresDbUtil.getCodeDb(path, schema, dbName);
                List<String> tableNamesForPG = ddlMapper.getTablesForPG(schema);
                List<ColumnVo> columnVosForPG = ddlMapper.getColumnInfoForPG(schema);
                for (TableEntity tableEntity : tableEntitiesForPG) {
                    PostgresTableEntity postgresTableEntity = (PostgresTableEntity) tableEntity;
                    Optional<String> any = tableNamesForPG.stream().filter(e -> e.equals(tableEntity.getTableName())).findAny();
                    if (any.isPresent()) {
                        // 找到表
                        List<ColumnVo> nowTableColumn = columnVosForPG.stream().filter(e -> e.getTableName().equals(any.get())).collect(Collectors.toList());
                        for (TableColumnEntity column : tableEntity.getColumns()) {
                            Optional<ColumnVo> any1 = nowTableColumn.stream().filter(e -> e.getColumnName().equals(column.getName())).findAny();
                            // auto 增删改  add 只能增 update 增改
                            if (any1.isPresent() && Arrays.asList("auto", "update").contains(ddlMode)) {
                                // 找到匹配字段 判断是否改动
                                Boolean aBoolean = PostgresDbUtil.columnCheck(column, any1.get());
                                if (!aBoolean) {
                                    String sql = PostgresDbUtil.updateColumn(column, any.get());
                                    ddlMapper.doExcuteSql(sql);
                                }
                            } else {
                                // 增加字段
                                String sql = PostgresDbUtil.addColumn(column, any.get());
                                ddlMapper.doExcuteSql(sql);
                            }
                        }
                        // 可删除权限
                        if (ddlMode.equals("auto")) {
                            List<ColumnVo> dropColumns = nowTableColumn.stream().filter(e ->
                                            !tableEntity.getColumns().stream().map(a -> a.getName()).collect(Collectors.toList()).contains(e.getColumnName()))
                                    .collect(Collectors.toList());
                            dropColumns.forEach(e -> {
                                String sql = PostgresDbUtil.deleteColumn(e, e.getTableName());
                                ddlMapper.doExcuteSql(sql);
                            });
                        }
                    } else {
                        String sql = PostgresDbUtil.generateTable(postgresTableEntity);
                        String generateSql = PostgresDbUtil.generateOwner(postgresTableEntity);
                        List<String> generateCommentSql = PostgresDbUtil.generateComment(postgresTableEntity);
                        if (StringUtils.isNotEmpty(sql) && StringUtils.isNotEmpty(generateSql))
                            ddlMapper.doExcuteSql(sql);
                        generateCommentSql.forEach(e -> {
                            try {
                                ddlMapper.doExcuteSql(e);
                            } catch (Exception exception) {
                                exception.printStackTrace();
                            }
                        });
                    }
                }
                break;
            default: {
            }
        }
        log.info(".......同步表结构结束");
    }
}
